﻿namespace EFS.Common.UI.Shared
{
	public class RadioButtonList : System.Windows.Controls.UserControl, System.Collections.Generic.IEnumerable<EFS.Common.UI.Shared.ListItem>
	{
		/// Class SelectedIndexChangedEventArgs
		public class SelectedIndexChangedEventArgs : System.EventArgs
		{
			public SelectedIndexChangedEventArgs(
				System.Int32? selectedIndex)
				: base()
			{
			}

			/// Property SelectedIndex: Get, Set
			public System.Int32? SelectedIndex { get; private set; }
		}

		#region delegates
		public delegate void SelectedIndexChangedDlg(RadioButtonList sender, SelectedIndexChangedEventArgs e);
		public SelectedIndexChangedDlg SelectedIndexChanged;
		#endregion

		#region Locals
		/// groupName
		private System.String groupName = System.Guid.NewGuid().ToString();

		/// itemsPadding
		private System.Double itemsMargin = 3;

		/// stack panel
		private System.Windows.Controls.StackPanel stackPanel = new System.Windows.Controls.StackPanel();

		/// radioButtonList
		private System.Collections.Generic.List<System.Windows.Controls.RadioButton> radioButtonList =
			new System.Collections.Generic.List<System.Windows.Controls.RadioButton>();

		/// items
		private System.Collections.Generic.List<EFS.Common.UI.Shared.ListItem> items =
			new System.Collections.Generic.List<EFS.Common.UI.Shared.ListItem>();
		#endregion

		#region Constructors
		/// Implicit
		public RadioButtonList()
		{
			// set defaults
			ItemsMargin = 2;

			// init stack panel
			stackPanel.VerticalAlignment = System.Windows.VerticalAlignment.Stretch;
			stackPanel.HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch;
			stackPanel.Orientation = System.Windows.Controls.Orientation.Vertical;

			// set content
			Content = stackPanel;

			// only if in design tool
#if SILVERLIGHT
			if (System.ComponentModel.DesignerProperties.IsInDesignTool)
#else
			if (System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
#endif
			{
				Add(new ListItem("1", "Radiobutton1"));
				Add(new ListItem("2", "Radiobutton2"));
			}
		}
		#endregion

		#region Properties
		/// Property GroupName: Get
		public System.String GroupName
		{
			get
			{
				return groupName;
			}
		}

		/// Property ItemsMargin: Get, Set
		public System.Double ItemsMargin
		{
			get
			{
				return itemsMargin;
			}
			set
			{
				itemsMargin = value;
				foreach(System.Windows.Controls.RadioButton radio in radioButtonList)
				{
					radio.Margin = ItemsInternalComputedMargin;
				}
			}
		}

		/// Property ItemsInternalComputedMarginItemsMargin: Get
		private System.Windows.Thickness ItemsInternalComputedMargin
		{
			get
			{
				return new System.Windows.Thickness(0, itemsMargin, 0, itemsMargin);
			}
		}

		/// Property SelectedIndex: Get, Set
		public System.Int32? SelectedIndex
		{
			get
			{
				for (System.Int32 i = 0; i < items.Count; ++i)
				{
					// get radio
					System.Windows.Controls.RadioButton radio = radioButtonList[i];

					// test selected
					if (radio.IsChecked.HasValue && radio.IsChecked.Value)
					{
						return i;
					}
				}

				// none
				return null;
			}
			set
			{
				if (!value.HasValue)
				{
					ClearSelection();
				}
				else
				{
					// verifyIndexRange
					VerifyIndexRange(value.Value);

					// test selection
					radioButtonList[value.Value].IsChecked = true;
				}
			}
		}

		/// Property ItemsCount: Get
		public System.Int32 ItemsCount
		{
			get
			{
				return items.Count;
			}
		}

		/// Property SelectedItem: Get
		public EFS.Common.UI.Shared.ListItem this[System.Int32 index]
		{
			get
			{
				// verify index
				VerifyIndexRange(index);

				// ok
				return items[index];
			}
		}

		/// Property SelectedItem: Get
		public EFS.Common.UI.Shared.ListItem SelectedItem
		{
			get
			{
				// get selected index
				System.Int32? selectedIndex = SelectedIndex;
				if (selectedIndex.HasValue)
				{
					return items[selectedIndex.Value];
				}

				// none
				return null;
			}
		}

		/// Property SelectedValue: Get
		public System.Object SelectedValue
		{
			get
			{
				// get selected item
				EFS.Common.UI.Shared.ListItem selectedItem = SelectedItem;

				// ok
				return null != selectedItem ? selectedItem.Value : null;
			}
			set
			{
				if (null == value)
				{
					ClearSelection();
				}
				else
				{
					for (System.Int32 i = 0; i < items.Count; ++i)
					{
						if (value.Equals(items[i].Value))
						{
							SelectedIndex = i;
							break;
						}
					}
				}
			}
		}
		#endregion

		#region Utilities
		/// VerifyIndexRange
		private void VerifyIndexRange(System.Int32 index)
		{
			// check
			EFS.Common.Verify.Condition(index >= 0 && index < ItemsCount, "Index out of bounds");
		}

		/// NotifySelectedIndexChanged
		private void NotifySelectedIndexChanged()
		{
			if (null != SelectedIndexChanged)
			{
				SelectedIndexChanged(
					this,
					new SelectedIndexChangedEventArgs(SelectedIndex));
			}
		}
		#endregion

		#region Handle list
		/// GetEnumerator
		System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
		{
			return items.GetEnumerator();
		}

		/// GetEnumerator
		public System.Collections.Generic.IEnumerator<EFS.Common.UI.Shared.ListItem> GetEnumerator()
		{
			return items.GetEnumerator();
		}

		/// Adds and element
		public void Add(
			EFS.Common.UI.Shared.ListItem item,
			System.Boolean selected)
		{
			// check
			EFS.Common.Verify.Reference(item, "item");

			// create new
			System.Windows.Controls.RadioButton radio = new System.Windows.Controls.RadioButton();
			radio.VerticalAlignment = System.Windows.VerticalAlignment.Center;
			radio.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
			radio.IsChecked = selected;
			radio.Content = item.Text;
			radio.GroupName = GroupName;
			radio.Margin = ItemsInternalComputedMargin;
			radio.Checked += new System.Windows.RoutedEventHandler(radio_Checked);
			radio.Unchecked += new System.Windows.RoutedEventHandler(radio_Unchecked);

			// add to lists
			radioButtonList.Add(radio);
			items.Add(item);

			// add to stack panel
			stackPanel.Children.Add(radio);
		}

		/// Adds and element
		public void Add(
			EFS.Common.UI.Shared.ListItem item)
		{
			Add(item, false);
		}

		/// Clear
		public void Clear()
		{
			// cicle all
			foreach (System.Windows.Controls.RadioButton radio in radioButtonList)
			{
				// remove delegates
				radio.Checked -= new System.Windows.RoutedEventHandler(radio_Checked);
				radio.Unchecked -= new System.Windows.RoutedEventHandler(radio_Unchecked);

				// invalidate group name
				radio.GroupName = System.Guid.NewGuid().ToString();
			}

			// remove from lists
			radioButtonList.Clear();
			items.Clear();

			// remove from stack panel
			stackPanel.Children.Clear();
		}

		/// ClearSelection
		public void ClearSelection()
		{
			// cicle all
			foreach (System.Windows.Controls.RadioButton radio in radioButtonList)
			{
				if (radio.IsChecked.HasValue && radio.IsChecked.Value)
				{
					radio.IsChecked = false;
				}
			}
		}
		#endregion

		#region Events
		/// radio_Checked
		private void radio_Checked(object sender, System.Windows.RoutedEventArgs e)
		{
			NotifySelectedIndexChanged();
		}

		/// radio_Unchecked
		private void radio_Unchecked(object sender, System.Windows.RoutedEventArgs e)
		{
			if (!SelectedIndex.HasValue)
			{
				NotifySelectedIndexChanged();
			}
		}
		#endregion
	}

}